package com.lincoln.framework.bean;

import com.lincoln.framework.exception.ErrorFormatException;
import com.lincoln.framework.interfaces.BaseProtocol;
import com.lincoln.framework.interfaces.MsgNoDeviceInfo;
import com.lincoln.util.ByteUtil;
import com.lincoln.util.CRC8Util;

import java.util.Arrays;

/**
 * 协议结构默认[头..][no][cmd长度][cmd..][payload.length][payload.length][payload.length][payload.length][payload][crc][尾..]
 * <p>
 * [payload.length]占4个字节
 *
 * @author lincoln
 * @date 2018/11/29
 */
public class AbstractMsgNoProtocol extends BaseProtocol {
    public static final byte[] HEAD_DATA = "18650021838{".getBytes();
    public static final byte[] TAIL_DATA = "}839185801".getBytes();

    /**
     * 消息号
     */
    private int no;

    /**
     * 指令长度
     */
    private int cmdLength;

    /**
     * 指令
     */
    private byte[] cmd;

    /**
     * payload长度
     */
    private int payloadLength;

    /**
     * payload
     */
    private byte[] payload;

    /**
     * crc
     */
    private byte crc;

    /**
     * 初始化
     *
     * @param no
     * @param cmd
     * @param payload
     */
    public AbstractMsgNoProtocol(int no, byte[] cmd, byte[] payload) {
        for (byte b : HEAD_DATA) {
            this.add(b);
        }

        this.no = no;
        this.add((byte) no);

        this.cmdLength = cmd.length;
        this.add((byte) cmd.length);

        this.cmd = cmd;
        for (byte b : cmd) {
            this.add(b);
        }

        this.payloadLength = (payload == null ? 0 : payload.length);
        for(byte b:ByteUtil.int2byte(payloadLength)){
            this.add(b);
        }

        this.payload = payload;
        for (byte b : payload) {
            this.add(b);
        }

        this.crc = CRC8Util.calcCrc8(payload);
        this.add(this.crc);

        for (byte b : TAIL_DATA) {
            this.add(b);
        }
    }

    /**
     * 初始化
     *
     * @param cmd
     * @param payload
     */
    public AbstractMsgNoProtocol(byte[] cmd, byte[] payload) {
        this(((MsgNoDeviceInfo) NettyContext.getDevice()).getNo(cmd), cmd, payload);
    }

    /**
     * 通过结果构建
     *
     * @param res
     */
    public AbstractMsgNoProtocol(byte[] res) throws ErrorFormatException {
        if (!Arrays.equals(HEAD_DATA, ByteUtil.sub(res, 0, HEAD_DATA.length)) || !Arrays.equals(TAIL_DATA, ByteUtil.sub(res, res.length - TAIL_DATA.length))) {
            throw new ErrorFormatException("包格式错误!");
        }
        this.no = res[HEAD_DATA.length];
        this.cmdLength = res[HEAD_DATA.length + 1];
        this.cmd = ByteUtil.sub(res, HEAD_DATA.length + 2, HEAD_DATA.length + 2 + cmdLength);
        //4位
        this.payloadLength = ByteUtil.byte2int(ByteUtil.sub(res, HEAD_DATA.length + 2 + cmdLength, HEAD_DATA.length + 6 + cmdLength));
        this.payload = ByteUtil.sub(res, HEAD_DATA.length + 6 + cmdLength, HEAD_DATA.length + 6 + cmdLength + payloadLength);

        this.crc = ByteUtil.sub(res, HEAD_DATA.length + 6 + cmdLength + payloadLength, HEAD_DATA.length + 7 + cmdLength + payloadLength)[0];
        if (this.crc != ByteUtil.sub(res, res.length - TAIL_DATA.length - 1, res.length - TAIL_DATA.length)[0]) {
            throw new ErrorFormatException("包格式错误!");
        }
        if (!verify()) {
            throw new ErrorFormatException("CRC校验出错!");
        }
        for (byte b : res) {
            this.add(b);
        }
    }

    /**
     * 获取消息号
     *
     * @return
     */
    public int getNo() {
        return this.no;
    }

    /**
     * 获取指令
     *
     * @return
     */
    @Override
    public byte[] getCmd() {
        return this.cmd;
    }

    /**
     * 获取包长
     *
     * @return
     */
    public int getLength() {
        return this.payloadLength;
    }

    /**
     * 获取数据包
     *
     * @return
     */
    public byte[] getPayload() {
        return this.payload;
    }

    /**
     * 获取md5
     *
     * @return
     */
    public byte getCrc() {
        return this.crc;
    }

    @Override
    public String toString() {
        String res = "";
        for (byte b : this) {
            res += Integer.toHexString(b) + ",";
        }
        res = res.substring(0, res.length() - 1);
        return res;
    }

    @Override
    public boolean verify() {
        if (this.crc != CRC8Util.calcCrc8(this.payload)) {
            return false;
        } else {
            return true;
        }
    }
}
